/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - RMI Client, FileChooser and WebDAV
 */
package de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.primary_data;

import java.io.IOException;
import java.io.OutputStream;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBException;

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

import io.milton.http.Auth;
import io.milton.resource.GetableResource;
import io.milton.resource.PropFindableResource;
import io.milton.http.Range;
import io.milton.http.Request;
import io.milton.http.Request.Method;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.http.exceptions.NotFoundException;

import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataDirectoryException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataEntityVersionException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.EdalException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaDataException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.security.EdalAuthenticateException;
import de.ipk_gatersleben.bit.bi.edal.publication.IpkAuthenticationProcess;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientDataManager;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataDirectory;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntity;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntityVersion;
import de.ipk_gatersleben.bit.bi.edal.rmi.server.Authentication;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.FileSystemCache;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.FileSystemHandler;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.metadata.ExtXMLConfig;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.metadata.Property;

/**
 * A resource representing a property.xml file for a specific version of a
 * PrimaryDataEntity.
 * 
 * @author benz
 * 
 */

public class PrimaryDataEntityPropertyVirtualResource implements
		GetableResource, PropFindableResource {
	private String content;
	private Property prop;
	private String name;
	private String filename;
	private long version;
	protected FileSystemHandler fileSystemHandler;

	public PrimaryDataEntityPropertyVirtualResource(
			ClientPrimaryDataEntityVersion v, long revision)
			throws JAXBException, MetaDataException {
		try {
			ExtXMLConfig conf = new ExtXMLConfig(Property.class);
			this.prop = new Property(v.getMetaData(), revision, v.isDeleted());
			this.content = conf.toString(prop);
			this.name = prop.getTitle();
			this.version = revision;
		} catch (RemoteException e) {
			ClientDataManager.logger
					.fatal("Failed to load/initialize FileSystemHandler: "
							+ e.getMessage());
		}

	}

	public PrimaryDataEntityPropertyVirtualResource(String filename,
			FileSystemHandler fs) throws JAXBException, RemoteException,
			PrimaryDataDirectoryException, NotBoundException,
			EdalAuthenticateException, PrimaryDataEntityVersionException,
			MetaDataException {
		String pathname = filename;
		String xmlfilename = filename;
		int idx = filename.lastIndexOf("/");

		if (idx > 0) {
			pathname = filename.substring(0, idx);
			xmlfilename = filename.substring(idx + 1);
		}

		Pattern p = Pattern
				.compile("(.*)\\.v([0-9]+)\\.?[^\\.]*\\.(properties\\.xml|.*)$");
		Matcher m = p.matcher(xmlfilename);

		if (m.matches() && fs != null) {
			ClientPrimaryDataEntity ent = fs.getEntity(pathname);
			if (ent != null) {
				long version = Long.valueOf(m.group(2));
				ClientPrimaryDataEntityVersion v = FileSystemHandler
						.getVersion(ent, version);
				ExtXMLConfig conf = new ExtXMLConfig(Property.class);
				this.prop = new Property(v.getMetaData(), version,
						v.isDeleted());
				this.content = conf.toString(prop);
				this.name = prop.getTitle();
				this.version = version;
			}
		}
	}

	@Override
	public Long getContentLength() {
		if (content == null) {
			return 0L;
		}
		long length = content.getBytes().length;
		return length;
	}

	@Override
	public String getContentType(String accepts) {
		return "text/xml";
	}

	@Override
	public Long getMaxAgeSeconds(Auth auth) {
		return 60L;
	}

	@Override
	public void sendContent(OutputStream out, Range range,
			Map<String, String> params, String contentType) throws IOException,
			NotAuthorizedException, BadRequestException, NotFoundException {
		out.write(content.getBytes());
	}

	@Override
	public Object authenticate(String user, String password) {
		Map info = new HashMap();
		info.put("user", user);
		info.put("password", password);
		return info;
	}

	@Override
	public boolean authorise(Request request, Method method, Auth auth) {
		if (auth == null || auth.getTag() == null) {
			return false;
		}

		Map info = (Map) (auth.getTag());
		String username = info.get("user").toString();
		if (FileSystemCache.get(username) != null) {
			return true;
		} else {
			//Authentication loginobj = new Authentication(username, info.get("password").toString());
			Authentication authentication = new Authentication(new IpkAuthenticationProcess().getSubject());
			try {
				/*
				ClientDataManager myClient = new ClientDataManager(
						FileSystemHandler.REGISTRY_PORT,
						FileSystemHandler.HOST, loginobj);
						*/
				ClientDataManager myClient = new ClientDataManager(FileSystemHandler.REGISTRY_PORT, FileSystemHandler.HOST, authentication);
				ClientPrimaryDataDirectory rootDirectory = myClient
						.getRootDirectory();

				fileSystemHandler = new FileSystemHandler(rootDirectory);
				FileSystemCache.put(username, fileSystemHandler);

				Pattern p = Pattern
						.compile("(.*)\\.v([0-9]+)\\.?[^\\.]*\\.(properties\\.xml|.*)$");
				Matcher m = p.matcher(filename);

				if (m.matches()) {
					ClientPrimaryDataEntity ent = fileSystemHandler.getEntity(m
							.group(1));
					long version = Long.valueOf(m.group(2));
					ClientPrimaryDataEntityVersion v = FileSystemHandler
							.getVersion(ent, version);
					ExtXMLConfig conf = new ExtXMLConfig(Property.class);
					this.prop = new Property(v.getMetaData(), version,
							v.isDeleted());
					this.content = conf.toString(prop);
					this.name = prop.getTitle();
					this.version = version;
				}
				return true;
			} catch (MetaDataException e) {
				e.printStackTrace();
			} catch (JAXBException e) {
				e.printStackTrace();
			} catch (RemoteException e) {
				ClientDataManager.logger
						.fatal("Failed to load/initialize FileSystemHandler: "
								+ e.getMessage());
			} catch (NotBoundException e) {
				ClientDataManager.logger
						.fatal("Failed to load/initialize FileSystemHandler: "
								+ e.getMessage());
			} catch (PrimaryDataDirectoryException e) {
				ClientDataManager.logger
						.fatal("Failed to load/initialize FileSystemHandler: "
								+ e.getMessage());
			} catch (EdalAuthenticateException e) {
				ClientDataManager.logger
						.fatal("Failed to load/initialize FileSystemHandler: "
								+ e.getMessage());
			} catch (EdalException e) {
				ClientDataManager.logger
						.fatal("Failed to load/initialize FileSystemHandler: "
								+ e.getMessage());
			}

		}

		return false;
	}

	@Override
	public String checkRedirect(Request request) {
		return null;
	}

	@Override
	public Date getModifiedDate() {
		return new Date(System.currentTimeMillis());
	}

	@Override
	public String getName() {
		Pattern p = Pattern
				.compile("(.*)\\.v[0-9]+\\.[^\\.]+\\.properties\\.xml$");
		Matcher m = p.matcher(name);

		// TODO handle filenames without extension
		if (m.matches()) {
			return m.group(1) + ".v" + version + "." + m.group(2)
					+ ".properties.xml";
		} else {
			return name + ".v" + version + ".properties.xml";
		}
	}

	@Override
	public String getRealm() {
		return null;
	}

	@Override
	public String getUniqueId() {
		return null;
	}

	@Override
	public Date getCreateDate() {
		return new Date(System.currentTimeMillis());
	}

}
